// $Id: reqpolsync.jsm 23 2012-04-06 15:30:28Z hhofer69@gmail.com $

"use strict";

Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("chrome://rpsmodules/content/common/syncutils.jsm");
Components.utils.import("chrome://rpsmodules/content/common/logutils.jsm");
Components.utils.import("chrome://reqpolsync/content/rpsutils.jsm");
Components.utils.import("chrome://reqpolsync/content/rpsengine.jsm");
Components.utils.import("resource://services-sync/main.js");

var EXPORTED_SYMBOLS = [ "RequestPolicySync" ];

//*****************************************************************************
//* Main class
//*****************************************************************************

var RequestPolicySync = {

  SYNC_ENGINE: "reqpolsync",
  
  data:     null,
  reqpol:   null,
  strings:  null,
  window:   null,
  ui:       null,

  startup: function RPS_startup(data, reason) {
    try {
      this.data = data;
      Services.strings.flushBundles();
      this.strings = new SyncStringBundle(this.SYNC_ENGINE);
    
      if (reason == 1) Services.obs.addObserver(this, "weave:service:ready",  false);
      else             this.startEngine();

      Services.obs  .addObserver(this, "addon-options-displayed", false);
      Services.obs  .addObserver(this, "reqpolsync-restored",     false);
      Services.prefs.addObserver("extensions.reqpolsync.reqpol", this, false);
      this.handleRequestPolicySettings();
      this.ui = new SyncUIAdder("reqpolsync", this.strings.get("reqpolsync"));
      Logging.debug("startup: " + reason);
    } catch (exc) {
      Logging.logException(exc);
      throw(exc);
    }
  },
  
  shutdown: function RPS_shutdown(data, reason) {
    try {
      let engine = Weave.Engines.get(this.SYNC_ENGINE);
      Logging.debug(engine ? ("unregistering '"+engine.Name+"'") :
                             ("Engine '"+this.SYNC_ENGINE+"' not registered"));
    
      if (this.ui) this.ui.close();

      if (engine) { 
        engine.shutdown();
        Weave.Engines.unregister(engine);
      } else {
        try { ReqPolCache.close(); } catch (exc) {}
      }

      try { Services.obs  .removeObserver(this, "addon-options-displayed"); } catch (exc) {}
      try { Services.obs  .removeObserver(this, "reqpolsync-restored");     } catch (exc) {}
      try { Services.prefs.removeObserver("extensions.reqpolsync.reqpol", this); } catch (exc) {}
    
      Logging.debug("shutdown: " + reason);
    } catch (exc) {
      Logging.logException(exc);
      throw(exc);
    }
  },
  
  observe: function RPS_observe(subject, topic, data) {
    try {
      Logging.debug("RPS_observe: " + subject + ", " + topic);

      switch (topic) {
        case "weave:service:ready":
          Services.obs.removeObserver(this, "weave:service:ready");
          this.startEngine();
          break;

        case "addon-options-displayed":
          if (this.data && data == this.data.id)
            this.handleOptions(subject);
          break;
        
        case "nsPref:changed":
          if (data == "extensions.reqpolsync.reqpol")
            this.handleRequestPolicySettings();
          break;
          
        case "reqpolsync-restored":
          let self = this;
          let win  = Services.wm.getMostRecentWindow('requestpolicy:pref') ||
                     Services.wm.getMostRecentWindow('navigator:browser');
          let ok = SyncUtil.promptAndSync(win, self.SYNC_ENGINE, "restoredPrompt");
          break;
      }
    } catch (exc) {
      Logging.logException(exc);
      throw(exc);
    }
  },
  
  startEngine: function RPS_startEngine() {
    try { this.reqpol = Components.classes["@requestpolicy.com/requestpolicy-service;1"].getService(Components.interfaces.nsIRequestPolicy); }
    catch (exc) {}
    
    if (this.reqpol === null) {
      Logging.warn("RequestPolicy doesn't seem to be installed. Exiting.");
      return;
    }

    this.migrate();

    if (!SyncUtil.lockWeave(10000)) {
      Logging.error("Cannot lock sync service. Engine not registered.");
      return;
    }

    try {

      Weave.Engines.register(RequestPolicySyncEngine);
      SyncUtil.assert(Weave.Engines.get(this.SYNC_ENGINE), "Engine failed to register");

      Logging.debug("Engine registered.");
        
      let backup = Services.prefs.getBoolPref("extensions.reqpolsync.autobak");
      
      if (this.isFirstStart()) {
        Logging.debug("First start");
        RequestPolicyBackup.firstStart(this, backup);
        let ok = SyncUtil.promptAndSync(null, this.SYNC_ENGINE);
      } else
        if (backup) RequestPolicyBackup.backup(this);
      
    } finally {
      Weave.Service.unlock();
    }
  },  

  handleOptions: function RPS_handleOptions(doc) {
    let self    = this;
    let reset   = doc.getElementById("rpsreset-btn");
    let backup  = doc.getElementById("rpsbackup-btn");
    let restore = doc.getElementById("rpsrestore-btn");
    let name    = this.strings.get("reqpolsync");
    
    if (Weave.Engines.get(this.SYNC_ENGINE) && Weave.Status.service == Weave.STATUS_OK) {
      // Show Reset Dialog
      reset.addEventListener("command", function RPS_onResetButton() {
        try { SyncUtil == undefined; } catch (exc) { alert("Please re-load this page!"); return; } // We've probably been re-installed...
        SyncUtil.promptAndSync(doc.defaultView, self.SYNC_ENGINE, "resetPrompt", "keepPrompt");
      }, false);
      if (ReqPolCache.reqpol) { // RequestPolicy is installed
        let rphandler = function RPS_onBackupRestore(evt) {
           self.handleRequestPolicyOptions(doc.defaultView, evt);
        };
        backup.addEventListener( "command", rphandler, false);
        backup.removeAttribute("oncommand");
        restore.addEventListener("command", rphandler, false);
        restore.removeAttribute("oncommand");
      }
    } else { // engine not (yet) registered, disable controls
      [ "rpsenabled-set", "rpsimmediate-set", "rpsmanage-set", "rpsautobak-set",
        "rpsreset-btn" /*, "rpsbackup-btn",    "rpsrestore-btn" */ ].forEach(function(id){
        doc.getElementById(id).setAttribute("disabled", "true");
      });
    }
    // <DevRelease>
    let debug   = doc.getElementById("rpsdebug-btn");
    debug.addEventListener("command", function RPS_onDebugButton() {
      RpsUtil.showDebugInfo()
    }, false);
    // </DevRelease>
  },  

  handleRequestPolicySettings: function RPS_handleRequestPolicySettings() {
    const REQPOL_SETTINGS = [
      "autoReload", "contextMenu",            "indicateBlockedObjects",
      "prefetch.dns.disableOnStartup",        "prefetch.dns.restoreDefaultOnUninstall",
      "prefetch.link.disableOnStartup",       "prefetch.link.restoreDefaultOnUninstall",
      "privateBrowsingPermanentWhitelisting", "privateBrowsingPermanentWhitelisting",
      "startWithAllowAllEnabled",             "statusbarIcon",
      "uriIdentificationLevel"
    ];
    let sync = Services.prefs.getBoolPref("extensions.reqpolsync.reqpol");
    let pfx  = "services.sync.prefs.sync.extensions.requestpolicy.";

    REQPOL_SETTINGS.forEach(function(pref) {
      if (sync) Services.prefs.setBoolPref(pfx + pref, "true");
      else      Services.prefs.clearUserPref(pfx + pref);
    });
  },

  handleRequestPolicyOptions: function RPS_handleRequestPolicyOptions(window, evt) {
    try {
      let dlg = window.openDialog("chrome://requestpolicy/content/prefWindow.xul",
                                  "requestpolicyPreferencesDialogWindow",
                                  "chrome, close, centerscreen, alwaysRaised");
      dlg.addEventListener("DOMContentLoaded", function RPS_loadRPPrefs(loadevt) {
        dlg.removeEventListener("DOMContentLoaded", RPS_loadRPPrefs, false);
        let newpane = null, msg = null;
        if      (evt.target.id == "rpsbackup-btn")
          newpane = dlg.document.getElementById("requestpolicyPrefpaneExport");
        else if (evt.target.id == "rpsrestore-btn")
          newpane = dlg.document.getElementById("requestpolicyPrefpaneImport");
        if (newpane) dlg.document.getElementById("requestpolicyPrefWindow")
                        .showPane(newpane);
      }, false);
    } catch (exc) {
      Logging.logException(exc);
    }
  },
  
  migrate: function RPS_migrate() {
    if (!this.reqpol) return; // nevermind, if RequestPolicy is not installed
    
    if (!ReqPolCache.dbdir.exists()) ReqPolCache.dbdir.create(1, 0x700);

    ReqPolCache.initDatabase();

    let ver = Services.prefs.getCharPref("extensions.reqpolsync.version");
    this._first = (ver == "") ||
                  ReqPolCache.db.getCount() == 0;

    ver  = ver.split(".");
    if (!(ver < this.data.version.split("."))) return;
    let mig = true;
    
    if (ver < [0,0,0]) {
      // migrate here
    } else
      mig = false;
      
    Services.prefs.setCharPref("extensions.reqpolsync.version", this.data.version);

    if (mig) Logging.debug("Migrated: '"+ver+"' -> '"+this.data.version+"'");
  },
  
  isFirstStart: function RPS_isFirstStart() {
    return this._first || Services.prefs.getCharPref("extensions.reqpolsync.version") == "";
  }
};
